#include "str.h"
#include "istr.h"
#include "fs.h"
#include <sstream>
#include <fstream>
#include <iomanip>
#include <regex>

using namespace std;

namespace log4x
{
string
str::to_str(int n)
{
    stringstream ss;
    ss << n;
    return ss.str();
}

string
str::to_str(uint32_t n)
{
    stringstream ss;
    ss << n;
    return ss.str();
}

string
str::to_str(int64_t n)
{
    stringstream ss;
    ss << n;
    return ss.str();
}

string
str::to_str(uint64_t n)
{
    stringstream ss;
    ss << n;
    return ss.str();
}

string
str::to_str(double f)
{
    stringstream ss;
    ss << f;
    return ss.str();
}

int
str::to_int(const string& s)
{
    stringstream ss;
    int num = 0;

    ss << s;
    ss >> num;
    return num;
}

uint32_t
str::to_int32(const string& s)
{
    stringstream ss;
    uint32_t num = 0;

    ss << s;
    ss >> num;
    return num;
}

uint64_t
str::to_int64(const string& s)
{
    stringstream ss;
    uint64_t num = 0;

    ss << s;
    ss >> num;
    return num;
}

double
str::to_float(const string& s)
{
    stringstream ss;
    double f = 0.0;

    ss << s;
    ss >> f;
    return f;
}

string
str::to_ipv4(uint32_t addr)
{
    //return os::net()->int2_ipv4(addr);
    return "";
}

string
str::to_ipv6(uint32_t* addr)
{
    return "";
}

string
str::to_hex(uint8_t num, bool prefix)
{
    stringstream ss;
    if (prefix)
    {
        ss << "0x" << hex << setw(2) << setfill('0') << (int)num;
    }
    else
    {
        ss << hex << setw(2) << setfill('0') << (int)num;
    }

    return ss.str();
}

string
str::to_hex(uint16_t num, bool prefix)
{
    stringstream ss;
    if (prefix)
    {
        ss << "0x" << hex << setw(4) << setfill('0') << num;
    }
    else
    {
        ss << hex << setw(4) << setfill('0') << num;
    }

    return ss.str();
}

string
str::to_hex(uint32_t num, bool prefix)
{
    stringstream ss;
    if (prefix)
    {
        ss << "0x" << hex << setw(8) << setfill('0') << num;
    }
    else
    {
        ss << hex << setw(8) << setfill('0') << num;
    }

    return ss.str();
}

string
str::hex_dump(const uint8_t data[], size_t size, int colnum, const string& delim)
{
    stringstream ss;

    for (size_t i = 0; i < size; ++i)
    {

        if (i != 0 && i % colnum == 0)
        {
            ss << '\n';
        }
        ss << hex << setw(2) << setfill('0') << (int)data[i];
        if (!delim.empty() && i != (size - 1))
        {
            ss << delim;
        }
    }

    return ss.str();
}

int 
str::to_bytes(const string &hex, uint8_t bytes[], size_t &size, const string &delim)
{
    std::stringstream ss;
    std::stringstream ssAll;
    ss << std::hex;
    for (size_t i = 0; i < hex.length();)
    {
        int val = 0;
        ss << std::hex << hex.substr(i, 2);
        ss >> val;
        ss.str("");
        ss.clear();
        ssAll << (char)val;
        i += 2 + delim.length();
    }
    size = ssAll.str().length();
    memcpy(bytes, ssAll.str().c_str(), size);
    return (int)size;
}

string
str::format(const char* fmt, ...)
{
    if (!fmt)
    {
        return "";
    }

    char buf[4 * 1024] = {0};
    int  result        = -1;

    va_list ap;
    va_start(ap, fmt);
    result = vsnprintf_s(buf, sizeof(buf), fmt, ap);
    va_end(ap);
    if (result <= 0)
    {
        return "";
    }
    return buf;
}

int
str::read_from_file(const string& fpath, string& data)
{
    std::ifstream in(fpath);
    if (!in.is_open())
    {
        return -1;
    }

    std::ostringstream oss;
    oss << in.rdbuf();
    in.close();
    data = oss.str();
    return (int)data.size();
}

int
str::write_to_file(const string& fpath, const string& data)
{
    string shortname = fs::shortname(fpath);
    if (!shortname.empty() && !fs::exists(shortname))
    {
        fs::mk_dir(shortname);
    }

    ofstream ofs(fpath);
    if (!ofs.is_open())
    {
        return -1;
    }

    ofs << data;
    ofs.close();
    return 0;
}

int
str::split(const string& in, const string& pattern, vector<string>& parts)
{
    if ("" == in || "" == pattern)
    {
        return -1;
    }

#if 0
    /**
     * 注意: 正则表达式特殊字符需要转义, 如:$^.[]{}\*+()|?
     * 当被分隔串第一个字符有分隔符时, 其执行结果与strtok不一样
     */
    std::regex re{ pattern };
    parts =
    {
        std::sregex_token_iterator(in.begin(), in.end(), re, -1),
        std::sregex_token_iterator()
    };
#else
    char* str = new char[in.size() + 1] ;
    strncpy(str, in.c_str(), in.size());
    str[in.size()] = '\0';

    char* saveptr = NULL;
    char* p = os::str()->strtok(str, pattern.c_str(), &saveptr);
    while (p)
    {
        parts.push_back(p);
        p = os::str()->strtok(NULL, pattern.c_str(), &saveptr);
    }
    delete []str;
#endif

    return 0;
}

string
str::strerror()
{
    return os::str()->strerror();
}

string
str::gsub(const string& src, const string& pattern, const string& replace)
{
    string res;
    string::size_type begin = 0;
    vector<string::size_type> pos;
    while ((begin = src.find(pattern, begin)) != string::npos)
    {
        pos.push_back(begin);
        begin += pattern.size();
    }

    if (pos.empty())
    {
        return src;
    }

    begin = 0;
    for (size_t i = 0; i < pos.size(); ++i)
    {
        res  += src.substr(begin, pos[i] - begin);
        res  += replace;
        begin = pos[i] + pattern.size();
    }

    res += src.substr(begin, string::npos);
    return res;
}

int
str::stricmp(const string& s1, const string& s2)
{
    return strcasecmp(s1.c_str(), s2.c_str());
}

int
str::strnicmp(const string& s1, const string& s2, size_t n)
{
    return strncasecmp(s1.c_str(), s2.c_str(), n);
}

string& 
str::trim(string& s)
{
    return lrtrim(s);
}

string&
str::ltrim(string &s)
{
    const string blanks("\f\v\r\t\n ");
    s.erase(0, s.find_first_not_of(blanks));
    return s;
}

string &
str::rtrim(string &s)
{
    const string blanks("\f\v\r\t\n ");
    s.erase(s.find_last_not_of(blanks) + 1);
    return s;
}

string &
str::lrtrim(string &s)
{
    return ltrim(rtrim(s));
}
}
